package com.yufei.pfw.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Field;
import org.springframework.data.mongodb.core.query.Order;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import com.mongodb.WriteResult;
import com.yufei.entity.AutoSequence;
import com.yufei.entity.Entity;
import com.yufei.pfw.DataRepository;
import com.yufei.utils.CommonUtil;
import com.yufei.utils.ExceptionUtil;
@Service
public class MongodbPfwService implements PfwService{
	private static Log mLog = LogFactory
			.getLog(MongodbPfwService.class);
	@Autowired DataRepository  dataRepository=null;
	
	
	
	
	
	public MongodbPfwService() {
		super();
		// TODO Auto-generated constructor stub
		
	}

	public DataRepository getDataRepository() {
		return dataRepository;
	}

	public void setDataRepository(DataRepository dataRepository) {
		this.dataRepository = dataRepository;
	}

	/* (non-Javadoc)
	 * key:fileName:operator(=,<,>,>=,<=,in,sort,like,limit,skip,nin,in)
	 * value:object(in(a,b,c))   sort:(a,d)
	 * @see com.yufei.pfw.service.PfwService#query(java.util.Map, java.lang.Class)
	 */
	@Override
	public <T> List<T> query(Map<String,Object> parametersMap,Class<T> t) {
         Query query=buildQuery(parametersMap, t);
        //可以添加缓存处理如果需要
		List<T> findList = dataRepository.getMongoTemplate().find(query, t);
		return findList;
		
	}

	@Override
	public <T> void update(T t) {
		// TODO Auto-generated method stub
		dataRepository.save(t);
		
	}

	@Override
	public <T> Long save(T t) {
		// TODO Auto-generated method stub'
		Entity entity=(Entity)t;
		if(entity.getId()==null){

		
		String className=t.getClass().getSimpleName();
		Update update=new Update();
		update.inc("sequence", 1);
	
		AutoSequence autoSequence=(AutoSequence) dataRepository.getMongoTemplate().findAndModify(new BasicQuery("{className:'"+className+"'}"), update, FindAndModifyOptions.options().returnNew(true).upsert(true), AutoSequence.class);
		
		entity.setId(autoSequence.getSequence());
		}
		dataRepository.save(entity);
		
		return entity.getId();

	}

	@Override
	public <T extends Entity> void delete(T t) {
		// TODO Auto-generated method stub
		dataRepository.removeEntity(t);
		
	}

	@Override
	@Deprecated
	public <T> List<T> query(String query, Class<T> t) {
		// TODO Auto-generated method stub
		 List<T> result=new ArrayList();
		 if(CommonUtil.isEmptyOrNull(query)){
			result= dataRepository.getMongoOperations().findAll(t);
		 }
		 
		 result=dataRepository.getMongoOperations().find(new BasicQuery(query), t);
		return result;
	}

	@Override
	public <T> List<T> query(List<QueryPaire> queryPaires, Class<T> t) {
		// TODO Auto-generated method stub
		
			Query query=buildQuery(queryPaires, t);


		
		
		//可以添加缓存处理如果需要
		List<T> findList = dataRepository.getMongoTemplate().find(query, t);
		return findList;
	}

	@Override
	public <T> long count(List<QueryPaire> queryPaires, Class<T> t)  {
		// TODO Auto-generated method stub
		Query query=buildQuery(queryPaires, t);
        return this.getDataRepository().getMongoTemplate().count(query, t);
	}

	

	private <T> Query buildQuery(List<QueryPaire> queryPaires, Class<T> t) {
		MyQuery query = new MyQuery();

		try {
			for(QueryPaire queryPaire: queryPaires){
				//sort:a/d;limit:number;skip:number;is:object;gt:number;lt:number;lte:number;gte:number;regex:str;in:s1,s2,se3;nin:s1,s2,s4;
	            //section:small,bigger
				//fields:field1,field2..
				//type.isAssignableFrom(String.class)
				String ov = queryPaire.getValue();
				Object fv=null;
				if(ov.startsWith("is")){
				//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
					Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
					fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1]);
					Criteria criteria=new Criteria(queryPaire.getKey());
					criteria.is(fv);
					query.addCriteria(criteria);
				}
				else if(ov.startsWith("regex")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1]);
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.regex((String) fv);
						query.addCriteria(criteria);
					}
				else if(ov.startsWith("section")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1].split(",")[0]);
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.gt(fv);
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1].split(",")[1]);
						criteria.lt(fv);

						query.addCriteria(criteria);
					}
				else if(ov.startsWith("gt")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1]);
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.gt(fv);
						
						query.addCriteria(criteria);
					}
				else if(ov.startsWith("gte")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1]);
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.gte(fv);
						query.addCriteria(criteria);
					}
				else if(ov.startsWith("lt")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1]);
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.lt(fv);
						query.addCriteria(criteria);
					}
				else if(ov.startsWith("lte")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						fv=CommonUtil.objectConvert(fieldCla, ov.split(":")[1]);
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.lte(fv);
						query.addCriteria(criteria);
						
					}
				else if(ov.startsWith("nin")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						
						List<Object> ins=new ArrayList<>();
						for(Object obj:ov.split(":")[1].split(",")){
							fv=CommonUtil.objectConvert(fieldCla, obj);
							ins.add(fv);
						}
						
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.nin(ins);
						query.addCriteria(criteria);
					}
				else if(ov.startsWith("in")){
					//	Class fieldCla=t.getField(queryPaire.getKey()).getType();
						Class fieldCla=CommonUtil.getFieldByFieldName(t,queryPaire.getKey()).getType();
						
						List<Object> ins=new ArrayList<>();
						for(Object obj:ov.split(":")[1].split(",")){
							fv=CommonUtil.objectConvert(fieldCla, obj);
							ins.add(fv);
						}
						
						Criteria criteria=new Criteria(queryPaire.getKey());
						criteria.in(ins);
						query.addCriteria(criteria);
					}
				
				else if(ov.startsWith("skip")){
					query.setSkip(Integer.parseInt(ov.split(":")[1]));
					
				}
				else if(ov.startsWith("limit")){
					query.setLimit(Integer.parseInt(ov.split(":")[1]));
				}
				else if(ov.startsWith("sort")){
					Order order=ov.split(":")[1].equals("a")==true?Order.ASCENDING:Order.DESCENDING;
					query.getMySort().on(queryPaire.getKey(),order);
				}
				//处理fields的情况
				else if(queryPaire.getKey()!=null&&queryPaire.getKey().equals("fields")){
					String[] fields=queryPaire.getValue().split(",");
					Field field=new Field();
				
					for(String filed1:fields){
						field.exclude(filed1);
					}
					query.setMyField(field);

				}
				
				
			}
		} catch (Exception e) {
			// TODO: handle exception
			String message = "你输入的查询表达式有误或者数据库连接有问题，具体错误信息是:"+ExceptionUtil.getExceptionDetailsMessage(e)+"";
			mLog.info(message);
	        
		}
		return query;
	}

private <T> Query buildQuery(Map<String, Object> parametersMap, Class<T> t) {
	MyQuery query = new MyQuery();
    if(parametersMap==null||parametersMap.size()==0){
	return query;
    }
    Criteria criteria=null;
	String[] fields=null;
	Object value=null;

    for(String field:parametersMap.keySet()){
    	criteria=null;
    	if(CommonUtil.isEmptyOrNull(field)){
    		continue;
    	}
    	value=parametersMap.get(field);
    	if(field.equals("limit")){
			query.setLimit((int)parametersMap.get(field));
			continue;

    	}
    	if(field.equals("skip")){
        	query.setSkip((int)parametersMap.get(field));
        	continue;
    	}
    	else{
    		fields=field.split(":");
        	String operator=fields[1];
        	switch (operator) {
        	
			case "=":
			    criteria=new Criteria(fields[0]);
				criteria.is(value);
				break;
			case "like":
				criteria=new Criteria(fields[0]);
				criteria.regex((String) value);
				break;
			case "gt":
			    criteria=new Criteria(fields[0]);
				criteria.gt(value);
				break;
			case "gte":
			    criteria=new Criteria(fields[0]);
				criteria.gte(value);
				break;
			case "lt":
			    criteria=new Criteria(fields[0]);
				criteria.lt(value);
				break;
			case "bw":
				Class fieldCla=CommonUtil.getFieldByFieldName(t,fields[0]).getType();
			    criteria=new Criteria(fields[0]);
			    String[] vs=((String)value).split("-");
				Object fv=CommonUtil.objectConvert(fieldCla, vs[0]);

				criteria.gte(fv);
				fv=CommonUtil.objectConvert(fieldCla, vs[1]);
				criteria.lte(fv);				
				break;
			case "lte":
			    criteria=new Criteria(fields[0]);
				criteria.lte(value);
				break;
			case "in":
				String fieldN=fields[0];
				if(fields[0].equals("_id")){
					fieldN=fields[0].replace("_", "");
				}
				 fieldCla=CommonUtil.getFieldByFieldName(t,fieldN).getType();

				List<Object> ins=new ArrayList<>();
				for(String obj:((String)value).split(",")){
					
					ins.add(CommonUtil.objectConvert(fieldCla, obj));
				}
				
				criteria=new Criteria(fields[0]);
				criteria.in(ins);
				break;
			case "nin":
				 fieldN=fields[0];
				if(fields[0].equals("_id")){
					fieldN=fields[0].replace("_", "");
				}
				 fieldCla=CommonUtil.getFieldByFieldName(t,fieldN).getType();

			     ins=new ArrayList<>();
				for(String obj:((String)value).split(",")){
					
					ins.add(CommonUtil.objectConvert(fieldCla, obj));
				}
				
				criteria=new Criteria(fields[0]);
				criteria.nin(ins);
				break;
			case "sort":
				String[] sortKeys=fields[0].split("#");
				String[] sortOrders=((String)value).split("#");
				for(int i=0;i<sortKeys.length;i++){
					Order order=sortOrders[i].equals("a")==true?Order.ASCENDING:Order.DESCENDING;
					query.getMySort().on(sortKeys[i],order);
				}
        		
 				break;
			default:
				break;
			}
    	}
    	if(criteria!=null){
    		query.addCriteria(criteria);

    	}

    	
    }
	
	return query;
	
}






@Override
public <T> void dropTable(Class<T> t) {
	// TODO Auto-generated method stub
	this.dataRepository.getMongoTemplate().dropCollection(t);
}

@Override
public <T> T query(String key, Object value, Class<T> t)
		 {
	// TODO Auto-generated method stub
	/*List<QueryPaire> queryPaires=new ArrayList<>();
	queryPaires.add(new QueryPaire(key, "is:"+value.toString()));
	List<T> tList=this.query(queryPaires, t);*/
	Map<String,Object> paraMap=new HashMap<>();
	paraMap.put(key+":=", value);
	List<T> tList=this.query(paraMap, t);
	if(CommonUtil.isEmptyOrNull(tList)){
		return null;

	}
	else return tList.get(0);
}

@Override
public <T> List<T> queryList(String key, Object value, Class<T> t)
		 {
	// TODO Auto-generated method stub
Map map=new HashMap(); 
if(key!=null||value!=null){
	map.put(""+key+":=",value);

	}
	List<T> tList=this.query(map, t);
	if(CommonUtil.isEmptyOrNull(tList)){
		return null;

	}
	else return tList;
}

@Override
public <T> void batchSave(List<T> ts) {
	// TODO Auto-generated method stub
	for(T t:ts){
		Entity entity=(Entity)t;
		if(entity.getId()==null){

		
		String className=t.getClass().getSimpleName();
		Update update=new Update();
		update.inc("sequence", 1);

		AutoSequence autoSequence=(AutoSequence) dataRepository.getMongoTemplate().findAndModify(new BasicQuery("{className:'"+className+"'}"), update, FindAndModifyOptions.options().returnNew(true).upsert(true), AutoSequence.class);
		
		entity.setId(autoSequence.getSequence());
		}
	}
	dataRepository.getMongoOperations().insertAll(ts);

	
}
@Override
public <T> void batchUpdate(List<T> ts) {
	// TODO Auto-generated method stub
	dataRepository.getMongoOperations().insertAll(ts);

}

@Override
public <T> T find(Class<T> t, Long id)  {
	// TODO Auto-generated method stub
	return this.query("id", id, t);
}

@Override
public <T> long remove(Object obj) {
	// TODO Auto-generated method stub
	dataRepository.getMongoTemplate().remove(obj);
	return 0;
}

@Override
public <T> long count(Map<String, Object> parametersMap, Class<T> t) {
	// TODO Auto-generated method stub
	Query query=buildQuery(parametersMap, t);
    return this.getDataRepository().getMongoTemplate().count(query, t);
}

@Override
public <T> long removeAll(Map<String, Object> parametersMap, Class<T> t) {
	// TODO Auto-generated method stub
	Query query=this.buildQuery(parametersMap, t);
	dataRepository.getMongoTemplate().remove(query, t);
	return 0;
}

@Override
public <T> long updateAll(Map<String, Object> parametersMap,
		Map<String,Object> setValuesMap, Class<T> t) {
	// TODO Auto-generated method stub
	Query query=this.buildQuery(parametersMap, t);
	Update update=new Update();
	//设置update的属性以及对应更新之后的值
	if(setValuesMap!=null&&setValuesMap.size()!=0){
		for(String  setField:setValuesMap.keySet()){
			update.set(setField, setValuesMap.get(setField));
		}
	}
	
	WriteResult writeResult=dataRepository.getMongoTemplate().updateMulti(query, update, t);
	return writeResult.getN();
}





}
